
pub mod room;
pub mod message;
pub mod play;

use chess::chessboard::Chessboard;
use chess::PieceColor;
use chess::ChessPiece;
use chess::ChessResult;
use self::room::GameRoom;

use self::message::{ChessCommand, PlayerResponse, ChessResponse};

use std::sync::mpsc;
use std::collections::HashMap;
use std::thread;
use std::time::Duration;

pub const PIECE_COUNT: u8 = 9;

///由一个单独线程处理。通过channel与外界通信。
/// 游戏循环。
pub fn game_loop(sender: mpsc::SyncSender<PlayerResponse>, receiver: mpsc::Receiver<ChessCommand>){
    let handle = thread::spawn( move ||{
        info!("Game loop running................");
        let mut room_map: HashMap<u32, room::GameRoom> = HashMap::new();
        loop{
            let message = receiver.try_recv();
            match message {
                Ok(command) => {
                    let vec = handle_game_message(command, &mut room_map);
                    for rsp in vec{
                        sender.send(rsp);
                    }
                },
                Err(e) => {
//                    error!("Receive message from net thread error: {:?}", e);
                    thread::sleep(Duration::from_millis(1000));
                }
            }
        }
    });
//    println!("{:?}", handle.join().unwrap());
}

fn handle_game_message(message: ChessCommand, mut room_map: &mut HashMap<u32, room::GameRoom>) -> Vec<PlayerResponse>{
    match message {
        ChessCommand::NewRoom(id, black, white) => create_new_room(id, black, white, &mut room_map),
        ChessCommand::PutPiece(room, player, location) => {
            if let Some(ref mut room) = room_map.get_mut(&room){
                play::put_piece(player, location, room)
            }else {
                vec![PlayerResponse::Error(player, "wrong_room_id".to_string())]
            }
        },
        ChessCommand::KillPiece(room, player, location) => {
            if let Some(ref mut room) = room_map.get_mut(&room){
                play::kill_piece(player, location, room)
            }else {
                vec![PlayerResponse::Error(player, "wrong_room_id".to_string())]
            }
        },
        ChessCommand::MovePiece(room, player, source, target) => {
            if let Some(ref mut room) = room_map.get_mut(&room){
                play::move_piece(player, source, target, room)
            }else {
                vec![PlayerResponse::Error(player, "wrong_room_id".to_string())]
            }
        },
        _ => Vec::<PlayerResponse>::with_capacity(2)
    }
}

///创建房间
fn create_new_room(id: u32, black: u32, white: u32, rooms: &mut HashMap<u32, GameRoom>) -> Vec<PlayerResponse>{
    let room = GameRoom::new(id, black, white);
    rooms.insert(id, room);
    //还需要返回消息给玩家，告知匹配成功。
    let mut vec = Vec::<PlayerResponse>::with_capacity(2);
    let black_message = PlayerResponse::MatchPlayer(black, white);
    let white_message = PlayerResponse::MatchPlayer(white, black);
    vec.push(black_message);
    vec.push(white_message);
    vec
}

#[derive(Eq, PartialEq)]
pub enum PlayerStage{
    Put, Move
}

pub struct ChessPlayer{
    id: u32,
    opponent: u32,
    pieces: Vec<ChessPiece>,
    stage: PlayerStage,
    color: PieceColor,
}

impl ChessPlayer{
    pub fn new(id: u32, other: u32, color: PieceColor) -> ChessPlayer{
        let mut pieces = Vec::with_capacity(PIECE_COUNT as usize);
        for i in 0..PIECE_COUNT{
            pieces.push(ChessPiece::new(color.clone()));
        };
        ChessPlayer{
            id,
            opponent: other,
            pieces,
            color,
            stage: PlayerStage::Put
        }
    }

    pub fn id(&self) -> u32{
        self.id
    }

    pub fn opponent(&self) -> u32{
        self.opponent
    }

    pub fn take_piece(&mut self) -> Option<ChessPiece>{
        self.pieces.pop()
    }

    pub fn player_stage(&self) -> &PlayerStage{
        &self.stage
    }

    pub fn color(&self) -> &PieceColor{
        &self.color
    }

    pub fn opponent_color(&self) -> PieceColor{
        match self.color {
            PieceColor::Black => PieceColor::White,
            PieceColor::White => PieceColor::Black
        }
    }

    pub fn is_move(&self) -> bool{
        PlayerStage::Move == self.stage
    }

    pub fn correct_stage(&mut self){
        if self.pieces.len() == 0{
            self.stage = PlayerStage::Move
        }
    }
}


pub struct SystemUser{
    user_id: u32,
    user_name: String,
    nickname: String,
}